'''
Class Name: Gui
Documentation :

TODO: Document each data member and member function
TODO: Elaborate the error messages. 
'''
#Author : Raghavendra Prasad <prasadr@cs.purdue.edu>


import os, string, random, time
from math import sqrt
import sys
sys.path.append("/home/raghavendra/code/version1/graph")
from graph import graph
from node import node
from edge import edge
from Tkinter import *
import tkMessageBox
import tkSimpleDialog
import Tkinter as tk
#Globals
center_distance = 10.0
circle_diameter = 20
scaling_factor = 1.0 
c_width = 1000
c_height = 670
border = 20

class Gui:
	root = Tk()
	frame = None
	canvas = None
	mainMenu = None
	rightMenu = None
	fileMenu = None
	editMenu = None
	helpMenu = None
	graph = None
	idToNode = {}
	idToEdge = {}
	idToText = {}
	currentNode = None
	currentType = None
	canAddNode = False

	def temp(self):
		print "hello"

	def quit(self):
		if tkMessageBox.askokcancel("Quit", "Do you really wish to quit?"):
			self.root.destroy()

	def __init__(self, graph):
		self.graph = graph
		self.root.protocol("WM_DELETE_WINDOW", self.quit)
		self.frame = Frame(self.root,width=1000,height=670)
		#self.frame.bind("<Button-1>",self.callback)
		self.frame.pack()
		self.makeCanvas()
		self.makeMenu()

	def makeMenu(self):
		self.mainMenu = Menu(self.root)
		self.root.config(menu=self.mainMenu)
		self.fileMenu = Menu(self.mainMenu, tearoff=0)
		self.fileMenu.add_cascade(label="New",command=self.temp)
		self.fileMenu.add_cascade(label="Open",command=self.temp)
		self.fileMenu.add_separator()
		self.fileMenu.add_cascade(label="Exit",command=self.quit)
		self.mainMenu.add_cascade(label="File",menu=self.fileMenu )
		self.editMenu = Menu(self.mainMenu, tearoff=0)
		self.editMenu.add_cascade(label="Node",command=self.temp)
		self.editMenu.add_cascade(label="Edge",command=self.temp)
		self.mainMenu.add_cascade(label="Edit",menu=self.editMenu )
	
	def makeCanvas(self):
		self.canvas = Canvas(self.frame, width=1000, height=670, relief=SUNKEN, bg="white", bd=2)
		self.canvas.pack()
		self.canvas.bind("<Button-3>",self.do_popup)
		self.canvas.bind("<Button-1>",self.left_callback)
		self.rightMenu = Menu(self.frame, tearoff=0)
		self.rightMenu.add_command(label="Remove",command=self.remove_node_callback)
		self.rightMenu.add_command(label="Add"  ,command=self.add_node_callback)

	def do_popup(self,event):
		try:
		        self.currentType = self.canvas.type(CURRENT)
			if self.canvas.type(CURRENT) == "rectangle":
				self.rightMenu.tk_popup(event.x_root, event.y_root, 0)
				tags = self.canvas.itemcget(CURRENT,"tags")
				self.currentNode = (tags.split(" ")[0]).strip()
				self.canAddNode = True #TODO: make it true and handle edge addition
			elif self.canvas.type(CURRENT) == "line":
				self.rightMenu.tk_popup(event.x_root, event.y_root, 0)
				tags = self.canvas.itemcget(CURRENT,"tags")
				print tags
				self.currentNode = (tags.split(" ")[0]).strip()
				self.canAddNode = False
			else:
				self.rightMenu.tk_popup(event.x_root, event.y_root, 0)
				self.canAddNode = True
		finally:
			self.rightMenu.grab_release()

	def add_node_callback(self):
		if self.canAddNode == True and self.currentType != "rectangle":
			node_id = tkSimpleDialog.askstring("Node", "Enter the new node id :")
			if node_id and not self.graph.getNode(node_id):
				self.graph.addNode(node_id)
				self.printNodes()
				node = self.graph.getNode(node_id)
				node.coordinate_x = random.random() * center_distance - (center_distance/2)
				node.coordinate_y = random.random() * center_distance - (center_distance/2)
				idArr = self.drawNode(node_id,"0C0") 
				print idArr
				node_widget_id = idArr[0]
				text_widget_id = idArr[1]
				if node_widget_id and text_widget_id:
					if not self.idToNode.has_key(node_id): self.idToNode[node_id] = node_widget_id
					if not self.idToText.has_key("text"+node_id): self.idToText["text"+node_id] =text_widget_id
		elif self.canAddNode == True and self.currentType == "rectangle":
			node_id = tkSimpleDialog.askstring("Edge", "Enter node to connect:")
			if node_id and self.graph.getNode(node_id):
				node = self.graph.getNode(self.currentNode)
				node2 = self.graph.getNode(node_id)
				
				self.graph.addEdge(node,node2)
				line_widget_id = self.drawEdge(node.id,node2.id,"0C0")
				if line_widget_id and line_widget_id not in self.idToEdge.keys():
					self.idToEdge[str(node.id)+"-"+str(node2.id)] = line_widget_id 

	def drawEdge(self,node1_id, node2_id,fill_color):
		line_widget_id = None
		node = self.graph.getNode(node1_id) 
		node2 = self.graph.getNode(node2_id) 
		if not node and not node2:
			return None
		x0 = ((node.coordinate_x*scaling_factor + (center_distance/2)) / center_distance * c_width) + border
		y0 = ((node.coordinate_y*scaling_factor + (center_distance/2)) / center_distance * c_height) + border
		node_id = str(node2.id) + "-"+str(node.id)
		if node_id in self.idToEdge.keys():
			return
		#if (node.id > node2.id):
		if node :
			x1 = ((node2.coordinate_x*scaling_factor + (center_distance/2)) / center_distance * c_width) + border
			y1 = ((node2.coordinate_y*scaling_factor + (center_distance/2)) / center_distance * c_height) + border
			line_widget_id = self.canvas.create_line (x0 + circle_diameter*scaling_factor / 2,\
					y0 + circle_diameter*scaling_factor / 2, \
				        x1 + circle_diameter*scaling_factor / 2, \
					y1 + circle_diameter*scaling_factor / 2, \
					width = 5,\
					tags = str(node2.id)+"-"+str(node.id))
			print "node id", node_id

		return line_widget_id

	def drawNode(self,node_id,fill_color ):
		node_widget_id = None
		text_widget_id = None
		node = self.graph.getNode(node_id) 
		if not node:
			print "FATAL ERROR id not found"
			return None
		x0 = ((node.coordinate_x*scaling_factor + (center_distance/2)) / center_distance * c_width) + border
		y0 = ((node.coordinate_y*scaling_factor + (center_distance/2)) / center_distance * c_height) + border
		if node.movable == 1:
			node_widget_id = self.canvas.create_rectangle(x0, y0,\
					x0 + circle_diameter*scaling_factor,\
					y0 + circle_diameter*scaling_factor,\
					fill="#" + fill_color, \
					tags = str(node.id))
		else:
			node_widget_id = self.canvas.create_rectangle(x0, y0, \
					x0 + circle_diameter*scaling_factor, \
					y0 + circle_diameter*scaling_factor, \
					fill="#000",\
					tags = str(node.id))
		text_widget_id = self.canvas.create_text(x0, y0 + circle_diameter*scaling_factor + 20, \
					anchor=tk.SW, text=str(node.id), \
					tags = "text"+str(node.id))
		print "node id", node.id, node_widget_id
		return [node_widget_id,text_widget_id]

	def remove_node_callback(self):
		if self.currentType == "rectangle" and self.currentNode in self.idToNode.keys():
			if tkMessageBox.askokcancel("Quit", "Do you really want to delet Node "+self.currentNode+"?"):
				self.canvas.delete(self.idToNode[(self.currentNode)])
				self.canvas.delete(self.idToText["text"+(self.currentNode)])
				node = self.graph.getNode(self.currentNode)
				node_id1 = None
				node_id2 = None
				node.deleteNeighbour(node.id)
				for neighbor_id in node.neighbour_ids:
					node2 = self.graph.getNode(neighbor_id)
					node2.deleteNeighbour(node.id)
					node_id1 = str(node.id) + "-"+str(node2.id)
					node_id2 = str(node2.id) + "-"+str(node.id)
					if node_id1 in self.idToEdge.keys():
						self.canvas.delete(self.idToEdge[node_id1])
						self.graph.removeEdge(node_id1)
					if node_id2 in self.idToEdge.keys():
						self.canvas.delete(self.idToEdge[node_id2])
						self.graph.removeEdge(node_id2)
				self.graph.removeNode(str(self.currentNode))
				self.idToNode.pop(self.currentNode)
				self.idToText.pop("text"+self.currentNode)
				print "idToText :", self.idToText
				print "isToNode :", self.idToNode
		elif self.currentType == "line" and (self.currentNode) in self.idToEdge.keys():
			if tkMessageBox.askokcancel("Quit", "Do you really want to delet Edge "+self.currentNode+"?"):
				self.canvas.delete(self.idToEdge[(self.currentNode)])
				self.graph.removeEdge(str(self.currentNode))
				self.idToEdge.pop(self.currentNode)
				print "idToEdge :", self.idToEdge
		self.root.update()
 	
	def right_callback(self,event):
		#print "right clicked ", event.x, event.y, event.widget
		self.rightMenu.post(event.x,event.y)

	def left_callback(self,event):
		self.rightMenu.unpost()

	def drawGraph(self):
		self.SetRandomNodePosition()
		node_widget_id = None
		line_widget_id = None
		text_widget_id = None
		#draw all edges
		fill_color = "0C0"
		for node in self.graph.getNodes():
			x0 = ((node.coordinate_x*scaling_factor + (center_distance/2)) / center_distance * c_width) + border
			y0 = ((node.coordinate_y*scaling_factor + (center_distance/2)) / center_distance * c_height) + border
			(node_widget_id, text_widget_id) = self.drawNode(node.id,"0C0")			
			self.idToNode[node.id] = node_widget_id
			self.idToText["text"+str(node.id)] = text_widget_id
			# draw all the edges to neighbors of this node
			for neighbor_id in node.neighbour_ids:
				node2 = self.graph.getNode(neighbor_id)
				line_widget_id = self.drawEdge(node.id,node2.id,"0C0")
				node_id = str(node2.id) + "-"+str(node.id)
				if line_widget_id and line_widget_id not in self.idToEdge.keys():
					self.idToEdge[node_id] = line_widget_id
		self.root.update()

        def SetRandomNodePosition(self):
		# sets random positions for all nodes
		for node in self.graph.getNodes():
			node.coordinate_x = random.random() * center_distance - (center_distance/2)
			node.coordinate_y = random.random() * center_distance - (center_distance/2)
	
	def printNodes(self):
		for node in self.graph.getNodes():
			print node.id
	
graphObj = Graph(4,"/home/raghavendra/code/PNet/data/input.in")
g = Gui(graphObj)
#print graphObj.getEdges()
#print graphObj.getNodes()
g.drawGraph()
g.printNodes()
g.root.mainloop()
